package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @author dylan
 * @version 0.0.0.1
 * description
 * @date: 2024/4/10 20:40
 */

public class NIOServer implements Runnable {
    // 通道管理器(Selector)
    private static Selector selector;

    @Override
    public void run() {
        System.out.println("准备开启。。。。。。。。。。。。。。。。。。");
        // 创建通道管理器(Selector)
        try {
            selector = Selector.open();
            // 创建通道ServerSocketChannel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 将通道设置为非阻塞
            serverSocketChannel.configureBlocking(false);

            // 将ServerSocketChannel对应的ServerSocket绑定到指定端口(port)
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(new InetSocketAddress(8989));

            /**
             * 将通道(Channel)注册到通道管理器(Selector)，并为该通道注册selectionKey.OP_ACCEPT事件
             * 注册该事件后，当事件到达的时候，selector.select()会返回，
             * 如果事件没有到达selector.select()会一直阻塞。
             */
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            // 循环处理
            while (true) {
                // 当注册事件到达时，方法返回，否则该方法会一直阻塞
                selector.select();
                // 获取监听事件
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();

                // 迭代处理
                while (iterator.hasNext()) {
                    System.out.println("迭代事件---------------------------");
                    // 获取事件
                    SelectionKey key = iterator.next();

                    // 移除事件，避免重复处理
                    iterator.remove();

                    try {
                        if (key.isAcceptable()) {
                            handleAccept(key);
                        } else if (key.isReadable()) {
                            handleRead(key);
                        }
                    } catch (IOException e) {
                        // 处理 IOException，可能是连接中断或其他异常
//                        e.printStackTrace();
                        System.out.println("通信异常关闭通道");
                        cancelKey(key);
                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void cancelKey(SelectionKey key) {
        try {
            // 取消注册
            key.cancel();
            // 关闭对应的 SocketChannel
            key.channel().close();
            System.out.println("Closed channel: " + key.toString());
            ChannelUtils.CHANNEL_MAP.remove(key.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理客户端连接成功事件
     */
    private static void handleAccept(SelectionKey key) throws IOException {
        // 获取客户端连接通道
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        SocketChannel socketChannel = server.accept();
        socketChannel.configureBlocking(false);

        // 信息通过通道发送给客户端
//        String msg = "Hello Client!";
//        socketChannel.write(ByteBuffer.wrap(msg.getBytes()));

        // 给通道设置读事件，客户端监听到读事件后，进行读取操作
        socketChannel.register(selector, SelectionKey.OP_READ);
        ChannelUtils.CHANNEL_MAP.putIfAbsent(key.toString(), socketChannel);
    }

    /**
     * 监听到读事件，读取客户端发送过来的消息
     */
    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();

        // 从通道读取数据到缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(128);
        channel.read(buffer);

        // 输出客户端发送过来的消息
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("server received msg from client：" + msg);
    }


}
